/**
 * @file ct_rtc.c
 * @brief Software implementation of I2C for 51 microcontroller.
 * @author David Xu
 * @version 1.0.0
 * @date 2023-11-09
 * @note none
 */
#include "ct_config.h"
#include "ct_rtc.h"

/**
 * @brief Enable RTC read/write access.
 */
// void _RTC_RWEN_(void) {
//     while (!(RTCRWEN & SET_BIT0))
//         ;
//     SFRS = 0;
// }

/**
 * @brief Starts the RTC module.
 *
 * This function enables the RTC to begin counting.
 */
void ct_rtc_Run(void) {
    RTC_Initial_Run();
    SFRS = 0;
}

/**
 * @brief Stops the RTC module.
 *
 * This function pauses the RTC, halting its counting temporarily.
 */
void ct_rtc_Pause(void) {
    RTC_Initial_Pause();
    SFRS = 0;
}

/**
 * @brief Sets the RTC date.
 *
 * @param[in] date Pointer to a RTC_Date_t structure containing the new date to set.
 * @note The function will not return a value but may modify hardware registers.
 * The Day of Week. [   \ref RTC_SUNDAY / \ref RTC_MONDAY / \ref RTC_TUESDAY /
 *                      \ref RTC_WEDNESDAY / \ref RTC_THURSDAY / \ref RTC_FRIDAY /
 *                      \ref RTC_SATURDAY ]
 */
void ct_rtc_SetDate(const RTC_Date_t *date) {
    if (date != NULL) {
        RTC_SetDate(date->year, date->month, date->day, date->dayOfWeek);
        SFRS = 0;
    }
}

/**
 * @brief Sets the RTC time.
 *
 * @param[in] time Pointer to a RTC_Time_t structure containing the new time to set.
 * @note The function will not return a value but may modify hardware registers.
 *      timeMode : The 12-Hour / 24-Hour Time Scale Selection. [ \ref RTC_CLOCK_12 / \ref RTC_CLOCK_24 ]
 *      AmPm :The AM / PM of 12-Hour Time Scale Selection. [ \ref RTC_AM / \ref RTC_PM ]
 */
void ct_rtc_SetTime(const RTC_Time_t *time) {
    if (time != NULL) {
        RTC_SetTime(time->hour, time->minute, time->second, time->timeMode, time->AmPm);
        SFRS = 0;
    }
}

/**
 * @brief Sets the RTC alarm date.
 *
 * @param[in] date Pointer to a RTC_Date_t structure containing the new alarm date to set.
 * @note The function will not return a value but may modify hardware registers.
 */
void ct_rtc_SetAlarmDate(const RTC_Date_t *date) {
    if (date != NULL) {
        RTC_SetAlarmDate(date->year, date->month, date->day);
        SFRS = 0;
    }
}

/**
 * @brief Sets the RTC alarm time.
 *
 * @param[in] time Pointer to a RTC_Time_t structure containing the new alarm time to set.
 * @note The function will not return a value but may modify hardware registers.
 *    TimeMode:    The 12-Hour / 24-Hour Time Scale Selection. [ \ref RTC_CLOCK_12 / \ref RTC_CLOCK_24 ]
 *     AmPm:        The AM / PM of 12-Hour Time Scale Selection. [ \ref RTC_AM / \ref RTC_PM ]
 */
void ct_rtc_SetAlarmTime(const RTC_Time_t *time) {
    if (time != NULL) {
        RTC_SetAlarmTime(time->hour, time->minute, time->second, time->timeMode, time->AmPm);
        SFRS = 0;
    }
}

/**
 * @brief Retrieves the current date and time from the RTC.
 *
 * @param[out] dateTime Pointer to a RTC_DateTime_t structure to store the current date and time.
 * @note The function will convert the S_RTC_TIME_DATA_T structure to RTC_DateTime_t structure.
 */
void ct_rtc_GetDateAndTime(RTC_DateTime_t *dateTime) {
    if (dateTime != NULL) {
        S_RTC_TIME_DATA_T rtcTimeData;
        RTC_GetDateAndTime(&rtcTimeData);

        // 进行必要的转换
        dateTime->date.year      = rtcTimeData.u16Year;
        dateTime->date.month     = rtcTimeData.u8Month;
        dateTime->date.day       = rtcTimeData.u8Day;
        dateTime->date.dayOfWeek = rtcTimeData.u8DayOfWeek;
        dateTime->time.hour      = rtcTimeData.u8Hour;
        dateTime->time.minute    = rtcTimeData.u8Minute;
        dateTime->time.second    = rtcTimeData.u8Second;
        dateTime->time.timeMode  = (rtcTimeData.u8TimeScale == 0) ? CT_RTC_CLOCK_12 : CT_RTC_CLOCK_24;
        dateTime->time.AmPm      = (rtcTimeData.u8AmPm == 0) ? CT_RTC_AM : CT_RTC_PM;
        SFRS                     = 0;
    }
}

/**
 * @brief Retrieves the current alarm date and time from the RTC.
 *
 * @param[out] dateTime Pointer to a RTC_DateTime_t structure to store the current alarm date and time.
 * @note The function will convert the S_RTC_TIME_DATA_T structure to RTC_DateTime_t structure.
 */
void ct_rtc_GetAlarmDateAndTime(RTC_DateTime_t *dateTime) {
    if (dateTime != NULL) {
        S_RTC_TIME_DATA_T rtcTimeData;
        RTC_GetAlarmDateAndTime(&rtcTimeData);

        dateTime->date.year      = rtcTimeData.u16Year;
        dateTime->date.month     = rtcTimeData.u8Month;
        dateTime->date.day       = rtcTimeData.u8Day;
        dateTime->date.dayOfWeek = rtcTimeData.u8DayOfWeek;
        dateTime->time.hour      = rtcTimeData.u8Hour;
        dateTime->time.minute    = rtcTimeData.u8Minute;
        dateTime->time.second    = rtcTimeData.u8Second;
        dateTime->time.timeMode  = rtcTimeData.u8TimeScale == 0 ? CT_RTC_CLOCK_12 : CT_RTC_CLOCK_24;
        dateTime->time.AmPm      = rtcTimeData.u8AmPm == 0 ? CT_RTC_AM : CT_RTC_PM;
        SFRS                     = 0;
    }
}

/**
 * @brief Enables a specified RTC interrupt.
 *
 * @param[in] intType The type of interrupt to enable. This can be one of the following:
 *                    - \ref CT_RTC_TIME_TICK for the time tick interrupt.
 *                    - \ref CT_RTC_ALARM for the alarm interrupt.
 * @note The function will not return a value but may modify hardware registers.
 */
void ct_rtc_EnableInterrupt(uint8_t intType) {
    RTC_Interrupt_Enable(intType);
    SFRS = 0;
}

/**
 * @brief Disables a specified RTC interrupt.
 *
 * @param[in] intType The type of interrupt to disable. This can be one of the following:
 *                    - \ref CT_RTC_TIME_TICK for the time tick interrupt.
 *                    - \ref CT_RTC_ALARM for the alarm interrupt.
 * @note The function will not return a value but may modify hardware registers.
 */
void ct_rtc_DisableInterrupt(uint8_t intType) {
    RTC_Interrupt_Disable(intType);
    SFRS = 0;
}

/**
 * @brief Selects the RTC clock source.
 *
 * @param[in] clockSource The clock source to be used for the RTC. This can be one of the following:
 *                        - \ref CT_RTC_CLK_LIRC_38P4K for the internal low-speed oscillator.
 *                        - \ref CT_RTC_CLK_LXT_32P768K for the external low-speed crystal.
 * @note The function will not return a value but may modify hardware registers.
 */
void ct_rtc_SelectClockSource(uint8_t clockSource) {
    RTC_Clock_Select(clockSource);
    SFRS = 0;
}

/**
 * @brief Initializes the RTC module with predefined date and time.
 *
 * This function sets up the RTC clock source, initializes the RTC with
 * the current date and time, enables the time tick interrupt, and starts
 * the RTC. If alarms are used, it also sets the alarm date and time and
 * enables the alarm interrupt.
 */
void ct_rtc_Init(void) {
    // 使用结构体来设置日期和时间
    RTC_Date_t currentDate = { 2023, 10, 2, CT_RTC_MONDAY };
    RTC_Time_t currentTime = { 0, 0, 0, CT_RTC_CLOCK_24, CT_RTC_AM };
#ifdef CT_RTC_USE_ALARMS
    // 使用结构体来设置闹钟日期和时间
    RTC_Date_t alarmDate = { 2023, 10, 2 };
    RTC_Time_t alarmTime = { 12, 0, 11, CT_RTC_CLOCK_12, CT_RTC_AM };
#endif
    /* Set RTC clock source */
    ct_rtc_SelectClockSource(CT_RTC_CLK_LIRC_38P4K);

    /* Pause RTC for setting */
    ct_rtc_Pause();

    /* Set current date and time */
    ct_rtc_SetDate(&currentDate);
    ct_rtc_SetTime(&currentTime);

    /* Enable RTC time tick interrupt */
    ct_rtc_EnableInterrupt(CT_RTC_TIME_TICK);

#ifdef CT_RTC_USE_ALARMS
    /* Set alarm date and time */
    ct_rtc_SetAlarmDate(&alarmDate);
    ct_rtc_SetAlarmTime(&alarmTime);

    /* Enable RTC alarm interrupt */
    ct_rtc_EnableInterrupt(CT_RTC_ALARM);
#endif

    /* Start RTC */
    ct_rtc_Run();
}
